/*
 * Copyright 2008 Stefan Henze
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

function $(id) { return document.getElementById(id); }
var iwat = new function() {
	
	var pageController = new function() {
		
		var animateX = -11;
		var animateInterval = 2;
		//var animateInterval = 200;
		var generalSwipeMode = "smooth";
		var currentPage = null;
		var currentHash = location.hash;
		var hashPrefix = "#_";
		var pageHistory = [];
		var preloadArray = [];

		var widgetControllers = {};
		this.registerWidgetController = function(widgetObject, widgetName) {
			widgetControllers[widgetName] = widgetObject;
		}
		
		//objects used frequently
		var toolbarEl, pageTitleEl, homeButtonEl, swipeContainer;
		
		addEventListener("load", function(event)
		{
			//prepare system
			toolbarEl = $("toolbar");
			pageTitleEl = $("pageTitle");
			homeButtonEl = $("homeButton");
			swipeContainer = $("swipecontainer");
			
			for (var child = document.body.firstChild; child; child = child.nextSibling)
			{
				if (child.nodeType == 1 && child.getAttribute("selected") == "true")
				{
					_showPage(child, false, null);
					break;
				}
			}
		
			setInterval(checkOrientAndLocation, 100);
			setTimeout(_hideAddress, 100);
			iwat.pc.updateOrientation();
			setTimeout(_preloadImages, 10);
		}, false);

		this.updateOrientation = function() {
			var or = "portrait";
			if (window.orientation && window.orientation != 0) {
				or = "landscape";
			}
			document.body.setAttribute("orientation", or);
			//setTimeout(_hideAddress, 100);
		}

		function handleClick(event) {
			var link = helper.findParent(event.target, "a");
			if (link) {
				event.preventDefault();
				var widget = link.getAttribute("widget");
				if (widget) {
					if (widgetControllers[widget]) {
						var cmd = link.getAttribute("cmd");
						widgetControllers[widget].perform(link, cmd);
					}
				} else if (link.hash) {
					var page = $(link.hash.substr(1));
					_showPage(page, false, link);
				}
			}
		}
		addEventListener("click", handleClick, true);
		
		this.showPage = function(page, backwards, link) {
			_showPage(page, backwards, link);
		};
		
		function _showPage(page, backwards, link)
		{
			if(page == null) { return;}
			location.href = currentHash = hashPrefix + page.id;
			pageHistory.push(page.id);
	
			var fromPage = currentPage;
			currentPage = page;
	
			pageTitleEl.innerHTML = page.title || "";
	
			if (homeButtonEl)
			{
				//homeButtonEl.style.display = (page.id) == "home" ? "none" : "inline";
				//TODO: Don't get parent using attributes but using page flow
				var parentName = page.getAttribute("parentName");
				if(parentName != undefined)
				{
					var parentEl = $(parentName);
					var parentTitle = parentEl.getAttribute("backtitle");
					if (!parentTitle) parentTitle = parentEl.title;
					homeButtonEl.style.display = "inline";
					homeButtonEl.innerHTML = parentTitle || "";
					homeButtonEl.href="#";
				} else {
					homeButtonEl.style.display = "none";
				}
			}
			if(fromPage) 
			{
				if (link) {
					link.setAttribute("selected", "true");
				}
				setTimeout(_swipePage, 0, fromPage, page, backwards, document.body, link);
			}
		}
		
		
		this.swipePage = _swipePage;
		function _swipePage(fromPage, toPage, backwards, parent, link, swipeMode) {
			if (!swipeMode) swipeMode = generalSwipeMode;
			switch (swipeMode) {
				case "fast":
					swipePageFast(fromPage, toPage, backwards, parent, link);
					break;
				case "smooth":
				default:
					swipePageFast(fromPage, toPage, backwards, parent, link);
					break;
			}
		}
		
		/*function swipePageSmooth(fromPage, toPage, backwards, parent, link) {
			//TODO: How do we do that for the slider widget?
			//TODO: swipe using scrollTo
			
			// Double the toolbar and move it to the right of the original one
			//TODO: Do we need to clone or can't we just update the state to a previously cloned version?
			var toolbar = $("toolbar");
			var toolbarClone = toolbar.cloneNode(true);
			toolbarClone.style.position = "absolute";
			toolbarClone.style.top = "0";
			toolbarClone.style.width = toolbar.offsetWidth + "px";
			toolbarClone.style.left = "100%";
			document.body.appendChild(toolbarClone);
			
			// Display the new page left to the current one
			var swipeContainer = $("swipecontainer");
			swipeContainer.innerHTML = "";
			swipeContainer.className = "swiping";
			swipeContainer.style.width = toolbar.offsetWidth + "px";
			swipeContainer.style.left = "100%";
			swipeContainer.appendChild(toPage);
			
		}
		
		function swipePageSmoothDo() {
			
		}*/


		function swipePageFast(fromPage, toPage, backwards, parent, link)
		{		
			toPage.setAttribute("selected", "true");
			var sp = backwards ? toPage : fromPage;
		
			_hideAddress();
			
			sp.setAttribute("style", "width: " + fromPage.offsetWidth + "px");
		
			parent.appendChild(swipeContainer);
			swipeContainer.innerHTML = "";
			swipeContainer.style.width = backwards ? "0%" : "100%";
			swipeContainer.className = "swiping";
			swipeContainer.appendChild(sp);
		
		
			var percent = 100;
			sp.className = sp.className + " swiping";
			window.setTimeout(swipePageFastDo, animateInterval, fromPage, percent, backwards, parent, link);
		};

		function swipePageFastDo(fromPage, percent, backwards, parent, link) {
			percent += animateX;
			if (percent <= 0)
			{
				percent = 0;
		
				swipeContainer.style.width = (backwards ? (100-percent) : percent) + "%";
		
				fromPage.removeAttribute("selected");
				var sp = swipeContainer.childNodes[0];
				parent.appendChild(sp);
				sp.removeAttribute("style");
				sp.className = sp.className.split(" swiping")[0];
				swipeContainer.className = "";
				if (link) {
					link.removeAttribute("selected");
				}
				
			} else {
				swipeContainer.style.width = (backwards ? (100-percent) : percent) + "%";
				window.setTimeout(swipePageFastDo, animateInterval, fromPage, percent, backwards, parent, link);
			}
		};
		
		function checkOrientAndLocation()
		{
			if (location.hash != currentHash)
			{
				currentHash = location.hash;
		
				var pageId = currentHash.substr(hashPrefix.length);
				var page = $(pageId);
				if (page)
				{
					var index = pageHistory.indexOf(pageId);
					var backwards = index != -1;
					if (backwards) {
						pageHistory.splice(index, pageHistory.length);
					 }
					pageController.showPage(page, backwards, null);
				}
			}
		}

 		this.hideAddress = _hideAddress;

		function _hideAddress() {
			window.scrollTo(0, 1); // pan to the bottom, hides the location bar
		}

		this.addPreload = function(url) {
			preloadArray.push(url);
		}
		function _preloadImages() {
			while (preloadArray.length > 0) {
				var img = new Image();
				img.src = preloadArray.pop();
			}
		}

	} ();

	/****************************************************************
	 * SLIDER WIDGET
	 ****************************************************************/
	this.widgetSlider = new function() {
		
		pageController.registerWidgetController(this, "slider");
		
		var sliderWidgets = {};
		
		this.perform = function(link, cmd) {
			var dir = (cmd=="left")?-1:1;
			slideTo(dir, link.parentNode.parentNode.parentNode.parentNode.parentNode);
		}
		
		this.initUsage = function(sliderId) {
			var slider = $(sliderId);
			var widget = {"id" : sliderId, "el" : slider};
			sliderWidgets[sliderId] = widget;
			var pages = [];
			var selectedPageIndex = 0;
			var numPages = 0;
			for (var i = 0; i < slider.childNodes.length; i++) {
				var currentNode = slider.childNodes[i];
				if (currentNode.nodeName.toUpperCase() == "DIV" && currentNode.className == "slideitem") {
					pages.push(currentNode);
					if (currentNode.getAttribute("selected") == "true") {
						selectedPageIndex = numPages;
					}
					numPages++;
				}
			}
			widget["pages"] = pages;
			
			widget["controller"] = slider.getElementsByTagName("table")[0];
			updateButtons(widget["controller"], selectedPageIndex, numPages);
		}
		
		function slideTo(direction, slider) {
			var widget = sliderWidgets[slider.id];
			
			var selectedPageIndex = 0;
			var pages = widget["pages"];
			for (var i=0; i<pages.length; i++) {
				if (pages[i].getAttribute("selected") == "true") {
					selectedPageIndex = i;
					break;
				}
			}
			
			if (selectedPageIndex + direction < 0 || selectedPageIndex + direction >= pages.length) {
				return;
			}
			
			var fromPage = pages[selectedPageIndex];
			var toPage = pages[selectedPageIndex + direction];
			var backwards = (direction < 0)?true:false;
			var sliderTitle = slider.getElementsByTagName("td")[1];
			sliderTitle.innerHTML = toPage.title || "";
		
			updateButtons(widget["controller"], selectedPageIndex+direction, pages.length);
			pageController.swipePage(fromPage, toPage, backwards, slider, null, "fast");
		}
		
		function updateButtons(controller, selectedPageIndex, numPages) {
			if (selectedPageIndex == 0) {
				helper.addClass(controller, "first");
			} else {
				helper.removeClass(controller, "first");
			}
			if (selectedPageIndex >= numPages-1) {
				helper.addClass(controller, "last");
			} else {
				helper.removeClass(controller, "last");
			}
		}
	}();
	
	/****************************************************************
	 * DIALOG WIDGET
	 ****************************************************************/
	var widgetDialog = new function() {
		//TODO: This might not work correctly with the back-button
		
		pageController.registerWidgetController(this, "dialog");

		var currentDialog = null;
		
		this.perform = function(link, cmd) {
			
			switch (cmd) {
				case "show":
					var page = $(link.hash.substr(1));
					showDialog(page);
					break;
				case "submit":
					var form = helper.findParent(link, "form");
					if (!form) return;
					form.submit();
					break;
				case "cancel":
					var form = helper.findParent(link, "form");
					if (!form) return;
					form.reset();
					hideDialog(form);
					break;
			}
		};
		
		function showDialog(form)
		{
			currentDialog = form;
			form.setAttribute("selected", "true");
			pageController.hideAddress();
			
			form.onsubmit = function(event)
			{
				event.preventDefault();
				form.removeAttribute("selected");
		
				var index = form.action.lastIndexOf("#");
				if (index != -1)
					pageController.showPage($(form.action.substr(index+1)));
			}
		
			form.onclick = function(event)
			{
				if (event.target == form)
					form.removeAttribute("selected");
			}
		}
		
		function hideDialog(form) {
			form.removeAttribute("selected");
			currentDialog = null;
			pageController.hideAddress();
		}



	}();
	
	/****************************************************************
	 * ARRANGER WIDGET
	 ****************************************************************/
	var widgetArranger = new function() {

		pageController.registerWidgetController(this, "arranger");

		this.perform = function(link, cmd) {
			var aEl = link.parentNode;
			var aElCont = aEl.parentNode;
			var arranger = aElCont.parentNode;
			switch (cmd) {
				case "hide":
					doArrangeHide(aEl, link);
					break;
				case "show":
					doArrangeShow(aEl, link);
					break;
				case "up":
					doArrangeUpDown(aEl, -1);
					break;
				case "down":
					doArrangeUpDown(aEl, 1);
					break;
				case "del":
					doDelStart(aEl, arranger, aElCont);
					break;
				case "delconfirm":
					doDelConfirm(aEl, arranger, aElCont);
					break;
			}
		}
		
		function doDelStart(aEl, arranger, aElCont) {
			if (aElCont.className.indexOf("delc") != -1) {
				removeDelMode(arranger);
			} else {
				removeDelMode(arranger);
				arranger.className = arranger.className + " delmode";
				aElCont.className = aElCont.className + " delc";
			}
		}
		
		function doDelConfirm(aEl, arranger, aElCont) {
			if (helper.hasClass(aElCont, "first")) {
				var node = aElCont.nextSibling;
				while (node && !(node.nodeType == "1" && helper.hasClass(node, "aec"))) {
					node = node.nextSibling;
				}
				if (node && node.nodeType == "1" && helper.hasClass(node, "aec")) {
					helper.addClass(node, "first");
					node.setAttribute("isFirst", "true");
				}
			}
			if (helper.hasClass(aElCont, "last")) {
				var node = aElCont.previousSibling;
				while (node && !(node.nodeType == "1" && helper.hasClass(node, "aec"))) {
					node = node.previousSibling;
				}
				if (node && node.nodeType == "1" && helper.hasClass(node, "aec")) {
					helper.addClass(node, "last");
					node.setAttribute("isLast", "true");
				}
			}
			arranger.removeChild(aElCont);
			helper.removeClass(arranger, "delmode");
		}
		
		function removeDelMode(arranger) {
			if (arranger.className.indexOf("delmode") == -1) return;
			helper.removeClass(arranger, "delmode");
			for (var i = 0; i < arranger.childNodes.length; i++) {
				var node = arranger.childNodes[i];
				if (node.nodeType == "1" && node.className.indexOf("delc") != -1) {
					helper.removeClass(node, "delc");
					break;
				}
			}
		}
		
		function doArrangeUpDown(aEl, dir) {
			var aElCont = aEl.parentNode;
			var arranger = aElCont.parentNode;
			var tElCont;
			if (dir == -1) {
				tElCont = aElCont.previousSibling;
				while (tElCont && !(tElCont.nodeType == "1" && helper.hasClass(tElCont, "aec"))) {
					tElCont = tElCont.previousSibling;
					
				}
			} else {
				tElCont = aElCont.nextSibling;
				while (tElCont && !(tElCont.nodeType == "1" && helper.hasClass(tElCont, "aec"))) {
					tElCont = tElCont.nextSibling;
				}
			}
			if (tElCont) {
				var tEl = tElCont.getElementsByTagName("div")[0];
				if (tEl) {
					/*tElCont.removeChild(tEl); //use this if no animation
					tElCont.appendChild(aEl);
					aElCont.appendChild(tEl);*/
					helper.addClass(aEl, "moving");
					window.setTimeout(upDownAnimate, 1, tElCont, tEl, aElCont, aEl, dir, 0);
				}
			}
		}
		
		function upDownAnimate(tElCont, tEl, aElCont, aEl, dir, percent) {
			percent += 30;
			if (percent >= 100) {
				aElCont.removeChild(aEl);
				aElCont.appendChild(tEl);
				helper.removeClass(aEl, "moving");
				aEl.style.top = "0px";
				tElCont.appendChild(aEl);
			} else {
				var pos = 40.0 * (percent / 100.0) * dir;
				aEl.style.top = pos.toFixed(0) + "px";
				window.setTimeout(upDownAnimate, 20, tElCont, tEl, aElCont, aEl, dir, percent);
			}
		}
		
		function doArrangeShow(aEl, link) {
			var aElCont = aEl.parentNode;
			var arranger = aElCont.parentNode;
			var divs = arranger.getElementsByTagName("div");
			var lastVisible, firstHidden, current;
			var between = []
			for (var i = 0; i < divs.length; i++) {
				current = divs[i];
				if (helper.hasClass(current, "aec")) {
					if (current.getAttribute("isLast")) {
						lastVisible = current;
					} else if (!firstHidden && current.getAttribute("hidden")) {
						firstHidden = current;
					} else if (current.getAttribute("hidden") && current != aElCont) {
						between.push(current);
					}
					if (current == aElCont) {
						break;
					}
				}
			}
			
			var swapUp = aElCont;
			for (var i = between.length-1; i >= 0 ; i--) {
				var dEl = between[i].getElementsByTagName("div")[0];
				var uEl = swapUp.getElementsByTagName("div")[0];
				between[i].removeChild(dEl);
				between[i].appendChild(uEl);
				swapUp.appendChild(dEl);
				swapUp = between[i];
			}
			
			var dEl = firstHidden.getElementsByTagName("div")[0];
			var uEl = swapUp.getElementsByTagName("div")[0];
			firstHidden.removeChild(dEl);
			firstHidden.appendChild(uEl);
			swapUp.appendChild(dEl);
			
			//TODO: remove extra attributes, just do it whith the class names
			firstHidden.setAttribute("isLast", "true");
			firstHidden.className = "aec last";
			firstHidden.removeAttribute("hidden");
			if (lastVisible) {
				lastVisible.removeAttribute("isLast");
				lastVisible.className = "aec";
				if (lastVisible.getAttribute("isFirst")) {
					lastVisible.className = "aec first";
				}
			} else {
				firstHidden.setAttribute("isFirst", "true");
				firstHidden.className = "aec first last";
			}
		
			link.className = "hide";
			link.setAttribute("cmd", "hide");
			
		}
		
		function doArrangeHide(aEl, link) {
			var aElCont = aEl.parentNode;
			var arranger = aElCont.parentNode;
			var divs = arranger.getElementsByTagName("div");
			var lastVisible, current;
			var currentFound = false;
			var between = []
			for (var i = 0; i < divs.length; i++) {
				current = divs[i];
				if (current.className.indexOf("aec") == 0) {
					if (!currentFound) {
						if (current == aElCont) {
							currentFound = true;
						}
					}
					if (currentFound){
						if (current.getAttribute("isLast")) {
							lastVisible = current;
						} else if (!current.getAttribute("hidden")) {
							between.push(current);
						} else {
							break;
						}
					}
				}
			}
			
			var swapDown = aElCont;
			window.setTimeout(hideAnimate, 50, between, swapDown, lastVisible, link, 0);
		}
		
		function hideAnimate(between, swapDown, lastVisible, link, i) {
			if (i < between.length) {
				var uEl = between[i].getElementsByTagName("div")[0];
				var dEl = swapDown.getElementsByTagName("div")[0];
				between[i].removeChild(uEl);
				between[i].appendChild(dEl);
				swapDown.appendChild(uEl);
				swapDown = between[i];
				i++;
				window.setTimeout(hideAnimate, 80, between, swapDown, lastVisible, link, i);
			} else {
				
				var dEl = lastVisible.getElementsByTagName("div")[0];
				var uEl = swapDown.getElementsByTagName("div")[0];
				lastVisible.removeChild(dEl);
				lastVisible.appendChild(uEl);
				swapDown.appendChild(dEl);
				
				lastVisible.setAttribute("hidden", "true");
				lastVisible.className = "aec";
				lastVisible.removeAttribute("isLast");
			
				if (swapDown == lastVisible && !swapDown.getAttribute("isFirst")) {
					swapDown = lastVisible.previousSibling;
					while (swapDown && !(swapDown.nodeType == "1" && swapDown.className.indexOf("aec") == 0)) {
						swapDown = swapDown.previousSibling;
					}
				}
				if (swapDown == lastVisible) {
					swapDown.removeAttribute("isFirst")
					swapDown.className = "aec";
				} else {
					swapDown.setAttribute("isLast", "true");
					swapDown.className = "aec last";
					if (swapDown.getAttribute("isFirst")) {
						swapDown.className = "aec last first";
					}
				}
				
			
				link.className = "show";
				link.setAttribute("cmd", "show");
			}	
		}
	}();


	var helper = new function() {
		this.removeClass = function(el, c) {
			var cn = el.className;
			el.className = cn.split(c).join("");
		}
		
		this.hasClass = function(el, c) {
			if (el.className.indexOf(c) != -1) {
				return true;
			} else {
				return false;
			}
		}
		
		this.addClass = function(el, c) {
			el.className = el.className + " " + c
		}
		this.findParent = function(node, localName) {
			while (node && (node.nodeType != 1 || node.localName.toLowerCase() != localName))
				node = node.parentNode;
			return node;
		}
		
	}
	this.h = helper;

	this.pi = pageController.addPreload;
	this.pc = pageController;
	
	//preloading images;
	//TODO: Does this work?
	this.pi("iwat/i/iPhoneToolbar.png");
	this.pi("iwat/i/toolButton2.png");
	this.pi("iwat/i/backButton2.png");
	this.pi("iwat/i/iPhoneArrow2.png");
	this.pi("iwat/i/listArrowSel.png");
	this.pi("iwat/i/selection.png");
	this.pi("iwat/i/rbleft.png");
	this.pi("iwat/i/rbright.png");
	this.pi("iwat/i/eyeon.gif");
	this.pi("iwat/i/eyeoff.gif");
	this.pi("iwat/i/del.gif");
	this.pi("iwat/i/delask.gif");
	this.pi("iwat/i/rbup.gif");
	this.pi("iwat/i/rbdown.gif");
	this.pi("iwat/i/redButton.png");
	this.pi("iwat/i/iPhoneToolbarLarge.png");
	this.pi("iwat/i/pinstripes.png");
	this.pi("iwat/i/radioBack.png");
	this.pi("iwat/i/radioBackSelected.png");

}();

// Used for scrolling in iphooney
var scrollingInterval;
function startScroll(direction) {
	var sc = 10 * direction;
	scrollingInterval = window.setInterval(function() {scrollBy(0,sc)}, 50);
}
function stopScroll() {
	window.clearInterval(scrollingInterval);
}


// register onOrientationChange event
function updateOrientation() {
	iwat.pc.updateOrientation();
}
window.onorientationchange=updateOrientation;


